package com.seleniti.enpareja.controller.ui.main;

import org.ioc.commons.flowcontrol.actioncontroller.ActionController;
import org.ioc.commons.flowcontrol.common.impl.ReceiverAdapter;
import org.ioc.commons.flowcontrol.eventbus.EventBus;
import org.ioc.commons.flowcontrol.logincontroller.IsLoggedUserInfoConsumer;
import org.ioc.commons.flowcontrol.logincontroller.LoginController.LogoutResponse;
import org.ioc.commons.flowcontrol.operationmanager.OperationManager;
import org.ioc.commons.flowcontrol.operationmanager.impl.OperationHandlerFactory;
import org.ioc.commons.ui.features.HasBoards;
import org.ioc.commons.utils.FormatterLogger;

import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.control.place.EnParejaPlace;
import com.seleniti.enpareja.controller.model.integration.database.domain.Couple;
import com.seleniti.enpareja.controller.model.integration.service.CoupleService;
import com.seleniti.enpareja.controller.ui.base.EnParejaBasePresenter;
import com.seleniti.enpareja.controller.ui.main.AppShell.Action;
import com.seleniti.enpareja.controller.ui.main.AppShell.Event;
import com.seleniti.enpareja.controller.ui.main.AppShell.Operation;

public class AppShellPresenter extends
		EnParejaBasePresenter<AppShell, AppShell.Event, AppShell.Operation, AppShell.Action> implements
		AppShell.Presenter, IsLoggedUserInfoConsumer<LoggedUserInfo> {

	private static final FormatterLogger logger = FormatterLogger.getLogger(AppShellPresenter.class);
	private CoupleService coupleService;

	public AppShellPresenter(AppShell display, EventBus<Event> eventbus, OperationManager<Operation> operationManager,
			ActionController<Action> actionController) {
		super(display, eventbus, operationManager, actionController);

	}

	@Override
	public void onInitDisplay() {
		super.onInitDisplay();
		this.coupleService = this.serviceManager.serviceFactory().coupleService();
		bindComponents();

		this.loginController.requiresLoggedUserInfo(this);
	}

	protected void bindComponents() {
		display.operationManager().bindOperation(Operation.MakingCouple,
				OperationHandlerFactory.<Operation> forLoaders(display.makingCoupleIndicator()));
	}

	@Override
	public void onLoggedUserInfoDataReady() {
		refreshLoggedUserInfo();
	}

	private void refreshLoggedUserInfo() {
		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();
		logger.info("Refreshing logged user info {0}...", lui);
		display.loggedUserInfo().setValue(lui);
		boolean loggedIn = lui != null && lui.isLogged();
		if (!loggedIn) {
			display.nonAssociatedPanelVisibility().setVisible(false);
			display.firstStepsVisibility().setVisible(false);
			display.nonAssociatedButtonVisibility().setVisible(!display.firstStepsVisibility().isVisible());
			display.pendingRequestsFromYouPanelVisibility().setVisible(false);
			display.rejectedRequestsFromYouPanelVisibility().setVisible(false);
			display.requestsToYouPanelVisibility().setVisible(false);
		}
	}

	@Override
	public boolean onGoBack() {
		boolean gone = tryGoBackBoard();

		if (!gone) {
			this.placeController.goBack();
		}
		return gone;
	}

	@Override
	public boolean onGoBackPressed() {
		return tryGoBackBoard();
	}

	private boolean tryGoBackBoard() {
		if (display.mainContainer().getSingleWidget() instanceof HasBoards<?>) {
			HasBoards<?> hb = (HasBoards<?>) display.mainContainer().getSingleWidget();
			boolean gone = hb.goBoardBack();
			if (gone) {
				/*
				 * Dont go back main view
				 */
				return true;
			}
		}

		return false;
	}

	@Override
	public void onLogout() {
		this.loginController.logout(new LogoutResponse<String>() {

			@Override
			public void onLogout(String externalLogoutUrl) {
				if (externalLogoutUrl != null) {
					logger.info("Opening logout url: {0}", externalLogoutUrl);
					display.openLink(externalLogoutUrl, false);
				}
			}
		});
	}

	@Override
	public void onLoggedUserInfoNotReadyYet() {
		/*
		 * Nothing to do
		 */
	}

	@Override
	public void onLoggedUserInfoDataUpdated(LoggedUserInfo loggedUserInfo) {
		refreshLoggedUserInfo();
	}

	@Override
	public void onOpenSelenitiWebSite() {
		display.openLink("http://www.seleniti.com", true);
	}

	@Override
	public void onOpenIocCommonsWebSite() {
		display.openLink("https://code.google.com/p/ioccommons/", true);
	}

	@Override
	public void onGoToCoupleRequestsView() {
		this.placeController.goTo(EnParejaPlace.CoupleRequests);
	}

	@Override
	public void onGoToGettingStartedView() {
		this.placeController.goTo(EnParejaPlace.GettingStarted);
	}

	@Override
	public void onDeleteNow() {
		this.actionController.invokeAction(Action.DeleteNow);
	}

	@Override
	public void onRefreshNow() {
		this.actionController.invokeAction(Action.RefreshNow);
	}

	@Override
	public void onOpenUserSettings() {
		this.placeController.goTo(EnParejaPlace.UserSettings);
	}

	@Override
	public void onGoToGetCoupleView() {
		this.placeController.goTo(EnParejaPlace.GetCouple);
	}

	@Override
	public void onSwitchElementsNow() {
		this.actionController.invokeAction(Action.SwitchElementsNow);
	}

	@Override
	public void onAuthFailure() {
		logger.error("Authentication failure");

		// TODO: Por hacer mensaje en pantalla
	}

	@Override
	public void onOpenAdminConsole() {
		this.placeController.goTo(EnParejaPlace.AdminConsole);
	}

	@Override
	public void onOpenWebSiteVersion() {
		display.openLink("http://www.enpareja.net", true);
	}

	@Override
	public void onOpenAppSettings() {
		this.placeController.goTo(EnParejaPlace.AppSettings);
	}

	@Override
	public void onMakeSingle() {
		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();
		if (lui != null && lui.isLogged()) {
			coupleService.makeSingle(lui.getUserId()).caller(this).performing(Operation.MakingCouple, operationManager)
					.to(new ReceiverAdapter<Couple>() {

						@Override
						public void success(Couple result) {
							logger.info("Refreshing logged user info...");
							display.firstStepsVisibility().setVisible(false);
							loginController.refreshLoggedUserInfo();
						}
					});
		} else {
			messageBoxFactory.alert("Modo soltero", "Debes entrar primero con un usuario en la aplicación");
		}
	}

	@Override
	public void onMakeTestCouple() {
		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();
		if (lui != null && lui.isLogged()) {
			coupleService.makeTestCouple(lui.getUserId()).caller(this)
					.performing(Operation.MakingCouple, operationManager).to(new ReceiverAdapter<Couple>() {

						@Override
						public void success(Couple result) {
							logger.info("Refreshing logged user info...");
							display.firstStepsVisibility().setVisible(false);
							loginController.refreshLoggedUserInfo();
						}
					});

		} else {
			messageBoxFactory.alert("Modo de prueba", "Debes entrar primero con un usuario en la aplicación");
		}
	}

	@Override
	public void onLoadBasics() {
		this.actionController.invokeAction(Action.LoadBasics);
	}
}
